package org.smile.beans;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.smile.beans.converter.BasicConverter;
import org.smile.beans.converter.Converter;
import org.smile.beans.property.IgnoreCasePropertyConverter;
import org.smile.beans.property.LikePropertyConverter;
import org.smile.beans.property.PropertyConverter;
import org.smile.exception.BeanException;
import org.smile.exception.ConvertException;


/**
 * beanutils 处理bean的一些方法工具类
 * 
 * @author strive
 *
 */
public class BeanUtils{

	@SuppressWarnings("unchecked")
	public static Map mapFromBean(Object bean) throws IntrospectionException, Exception{
		Class c=bean.getClass();
		PropertyDescriptor[] propertys= Introspector.getBeanInfo(c).getPropertyDescriptors();
		Map map=new HashMap();
		for(int i=0;i<propertys.length;i++){
			PropertyDescriptor p=propertys[i];
			Method getter=p.getReadMethod();
			Object value=getter.invoke(bean, new Object[]{});
			map.put(p.getName(), value);
		}
		map.remove("class");
		return map;
	}
	/**
	 * map 转成 bean
	 * @param map
	 * @param bean
	 * @return
	 * @throws ConvertException 
	 * @throws IntrospectionException
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static Object mapToBean(Map map,Object bean) throws ConvertException{
		return mapToBean(map,bean,new BasicConverter());
	}
	/**
	 * map 模糊转入 bean  以不分大小写 忽略下划线的 原则
	 * @param map
	 * @param bean
	 * @return
	 * @throws ConvertException
	 * @throws IntrospectionException
	 */
	public static Object mapLikeToBean(Map map,Object bean) throws ConvertException{
		try{
			return mapToBean(map,bean,new LikePropertyConverter(bean.getClass()),new BasicConverter(),false);
		}catch(IntrospectionException e){
			throw new ConvertException(e);
		}
	}
	/**
	 * 把 map 转成 bean  以key 和 属性不分大小写的原原则转换
	 * @param map
	 * @param bean
	 * @return
	 * @throws ConvertException
	 */
	public static Object mapIgnoreCaseToBean(Map map,Object bean) throws ConvertException {
		try{
			return mapToBean(map,bean,new IgnoreCasePropertyConverter(bean.getClass()),new BasicConverter(),false);
		}catch(IntrospectionException e){
			throw new ConvertException(e);
		}
	}
	/**
	 * 模糊转换 可以把 first_name key 转成 bean 中的 firstName或firstname 属性
	 * @param map
	 * @param bean
	 * @return
	 * @throws ConvertException 
	 */
	public static Object mapToBean(Map map,Object bean,PropertyConverter propertyConverter,Converter converter,boolean isNullTo ) throws ConvertException{
		try{
			Set keySet=map.keySet();
			for(Iterator iterator=keySet.iterator();iterator.hasNext();){
				String key=(String)iterator.next();
				PropertyDescriptor property=propertyConverter.keyToProperty(key);
				if(property!=null){
					Method setter=property.getWriteMethod();
					Method getter=property.getReadMethod();
					Class type=property.getPropertyType();
					if(setter!=null){
						Object value=map.get(key);
						if(value!=null||isNullTo){
							//泛型
							Class[] generic=null;
							try{
								ParameterizedType pt=(ParameterizedType)getter.getGenericReturnType();
								Type[] genericType=pt.getActualTypeArguments();
								generic=new Class[genericType.length];
								for(int j=0;j<genericType.length;j++){
									generic[j]=(Class)genericType[j];
								}
							}catch(Exception e){}
							//转换类型
							value=converter.convert(type,generic,value);
							setter.invoke(bean, new Object[]{value});
						}
					}
				}
			}
		}catch(Exception e){
			throw new ConvertException(e.getMessage(),e);
		}
		return bean;
	}
	/**
	 * 从map创建一个bean
	 * @param c 
	 * @param map
	 * @return
	 * @throws BeanException
	 */
	public static Object newBean(Class c,Map map) throws BeanException{
		try{
			Object bean=c.newInstance();
			PropertyDescriptor[] propertys= Introspector.getBeanInfo(c).getPropertyDescriptors();
			PropertyDescriptor property;
			for(int i=0;i<propertys.length;i++){
				property=propertys[i];
				Method setter=property.getWriteMethod();
				if(setter!=null){
					String key=property.getName();
					Object value=map.get(key);
					if(value!=null){
						setter.invoke(bean, new Object[]{value});
					}
				}
			}
			return bean;
		}catch(Exception e){
			throw new BeanException(e);
		}
	}
	/**
	 * map 转数据到bean 中
	 * @param map
	 * @param bean
	 * @param converter
	 * @return
	 * @throws ConvertException
	 */
	@SuppressWarnings("unchecked")
	public static Object mapToBean(Map map,Object bean,Converter converter) throws ConvertException{
		return mapToBean(map,bean,converter,false);
	}
	/**
	 * map 转换成 bean
	 * @param map
	 * @param bean
	 * @param converter
	 * @param isNullTo
	 * @return
	 * @throws ConvertException
	 */
	@SuppressWarnings("unchecked")
	public static Object mapToBean(Map map,Object bean,Converter converter,boolean isNullTo) throws ConvertException{
		Class c=bean.getClass();
		try{
			PropertyDescriptor[] propertys= Introspector.getBeanInfo(c).getPropertyDescriptors();
			PropertyDescriptor property;
			for(int i=0;i<propertys.length;i++){
				property=propertys[i];
				Method setter=property.getWriteMethod();
				Method getter=property.getReadMethod();
				Class type=property.getPropertyType();
				if(setter!=null){
					String key=property.getName();
					Object value=map.get(key);
					if(value!=null||isNullTo){
						//泛型
						Class[] generic=null;
						try{
							ParameterizedType pt=(ParameterizedType)getter.getGenericReturnType();
							Type[] genericType=pt.getActualTypeArguments();
							generic=new Class[genericType.length];
							for(int j=0;j<genericType.length;j++){
								generic[j]=(Class)genericType[j];
							}
						}catch(Exception e){}
						//转换类型
						value=converter.convert(type,generic,value);
						setter.invoke(bean, new Object[]{value});
					}
				}
			}
		}catch(Exception e){
			throw new ConvertException(e.getMessage(),e);
		}
		return bean;
	}
	/**
	 * get data form request convert to a bean 
	 * @param request
	 * @param bean
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static Object requestToBean(HttpServletRequest request,Object bean) throws Exception {
		
		Map<String, Object> map = new HashMap<String, Object>();
		Enumeration enuma = request.getParameterNames();
		while (enuma.hasMoreElements()) {
			String key = (String) enuma.nextElement();
			String[] value= (String[]) request.getParameterValues(key); 
			if (null == value || value.length==0) {
				continue;
			}
			map.put(key,value);
		}
		return mapToBean(map,bean,new BasicConverter());
	}
}